/*
 * @Copyright: 2017 www.yyfax.com Inc. All rights reserved.
 */
package com.yyfax.pay.order.service;

import com.yyfax.commons.json.JacksonUtil;
import com.yyfax.commons.lang.DateUtil;
import com.yyfax.framework.common.Log;
import com.yyfax.framework.common.OpResponse;
import com.yyfax.framework.exception.YYException;
import com.yyfax.framework.model.YYFaxRsp;
import com.yyfax.framework.yyfax.CryptUtil;
import com.yyfax.framework.yyfax.DesensitizationUtil;
import com.yyfax.framework.yyfax.enums.CurrencyEnum;
import com.yyfax.framework.yyfax.enums.YesNoEnum;
import com.yyfax.pay.common.constants.PayConstants;
import com.yyfax.pay.common.enums.*;
import com.yyfax.pay.common.exception.PayExceptionCode;
import com.yyfax.pay.common.exception.YYPayException;
import com.yyfax.pay.common.util.CheckSignUtils;
import com.yyfax.pay.common.util.PayoutIdUtil;
import com.yyfax.pay.config.data.service.MerchantConfigService;
import com.yyfax.pay.config.model.po.MerchantConfigPO;
import com.yyfax.pay.order.data.service.PayoutBatchOrderLogService;
import com.yyfax.pay.order.data.service.PayoutBatchOrderService;
import com.yyfax.pay.order.data.service.PayoutOrderLogService;
import com.yyfax.pay.order.data.service.PayoutOrderService;
import com.yyfax.pay.order.model.po.PayoutBatchOrderLogPO;
import com.yyfax.pay.order.model.po.PayoutBatchOrderPO;
import com.yyfax.pay.order.model.po.PayoutOrderLogPO;
import com.yyfax.pay.order.model.po.PayoutOrderPO;
import com.yyfax.pay.order.model.to.*;
import com.yyfax.pay.order.model.to.PayoutBatchOrderParams.PayoutOrder;
import com.yyfax.pay.order.model.to.PayoutBatchResultNotifyParams.PayoutBatchResultNotify;
import com.yyfax.pay.order.model.to.PayoutBatchResultNotifyParams.PayoutBatchResultNotify.PayoutResultNotify;
import com.yyfax.pay.order.model.to.PayoutResultNotifyParams.PayoutNotifyParams;
import com.yyfax.pay.order.model.vo.PayoutBatchOrderVO;
import com.yyfax.pay.order.model.vo.PayoutOrderVO;
import com.yyfax.pay.third.model.to.yyfax.*;
import com.yyfax.pay.third.model.to.yyfax.PayoutBatchOrderYYParams.PayoutOrderYY;
import com.yyfax.pay.third.model.to.yyfax.QueryBatchPayoutOrderYYContent.QueryPayoutOrder;
import com.yyfax.pay.third.service.ThirdPayService;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.dao.DuplicateKeyException;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;

/**
 * 代付业务服务
 * 
 * @author buyi
 * @date 2017-04-18 09:54:21
 * @since v1.0.0
 */
@Service
public class PayoutService {
	private Logger logger = LoggerFactory.getLogger(getClass());

	@Autowired
	private PayoutOrderService payoutOrderService;

	@Autowired
	private PayoutOrderLogService payoutOrderLogService;

	@Autowired
	private PayoutBatchOrderService payoutBatchOrderService;

	@Autowired
	private PayoutBatchOrderLogService payoutBatchOrderLogService;

	@Autowired
	private AdapterService adapterService;

	@Autowired
	private MerchantConfigService merchantConfigService;

	@Autowired
	private PayCommonService payCommonService;

	@Autowired
	private PayConstants payConstants;

	@Resource
	private PayoutIdUtil payoutIdUtil;

	/**
	 * 保存代付订单，并返回业务主键
	 * 
	 * @author buyi
	 * @date 2017-04-18 10:03:43
	 * @since v1.0.0
	 * @param params
	 * @return
	 * @throws Throwable
	 */
	public PayoutOrderVO savePayoutOrder(String merchantCode, PayoutOrderParams params) throws Throwable {
		final String op = "PayoutService.savePayoutOrder";
		PayoutOrderVO vo = new PayoutOrderVO();

		PayoutOrderPO po = new PayoutOrderPO();
		BeanUtils.copyProperties(params, po);

		po.setMerchantCode(merchantCode);
		po.setUserId(params.getUserId());
		po.setOrderId(params.getOrderId());
		po.setOrderTime(params.getOrderTime());

		if (StringUtils.isBlank(params.getExpireTime())) {
			long expireTime = DateUtil.str2DateTime(po.getOrderTime()).getTime() + payConstants.getDefaultExpireTime();
			po.setExpireTime(DateUtil.milli2str(expireTime));
		} else {
			po.setExpireTime(params.getExpireTime());
		}

		po.setPaymentCode(params.getPaymentCode());
		po.setPayeeCardNo(DesensitizationUtil.convertBankCard(params.getPayeeCardNo()));
		po.setPayeeCardNoCip(CryptUtil.encrypt(params.getPayeeCardNo()));
		po.setPayeeName(params.getPayeeName());
		po.setAmount(params.getAmount());
		po.setServerIp(params.getServerIp());

		po.setCurrency(CurrencyEnum.RMB.getValue());
		po.setActPaymentCode(params.getPaymentCode());

		po.setState(OrderStateEnum.INI.getValue());

		po.setRefundUrl(params.getRefundUrl());

		// 代付业务根据支付通道，生成支付公司相应的业务流水号
		// String busiId = CommonIdUtils.generateId(PayTypeEnum.PAY_OUT, po.getMerchantCode(), po.getOrderId());
		// 生成业务流水号
		String busiId = payoutIdUtil.generatePayoutBusiId(params.getPaymentCode(), merchantCode);

		po.setPayoutOrderId(busiId);
		po.setCreateTime(DateUtil.getCurrentDateTime());

		try {
			// payoutOrderService.saveAndReturnBusiKey(po);
			payoutOrderService.save(po);
			vo.setPayoutOrderPO(po);
		} catch (DuplicateKeyException e) {
			logger.warn(Log.op(op).msg("保存代付订单信息出现主键冲突，走幂等流程,查询订单信息").kv("merchantCode", merchantCode).kv("orderId", params.getOrderId()).toString());
			// 查询订单
			vo = payoutOrderService.queryPayoutOrderVOByOrderId(params.getOrderId(), merchantCode);
			if (vo == null) {
				logger.error(Log.op(op).msg("保存订单信息主键冲突,查询订单的不存在").kv("merchantCode", merchantCode).kv("orderId", params.getOrderId()).toString());
				throw PayExceptionCode.ORDER_NOT_FOUND.exp();
			}
		}

		return vo;
	}

	/**
	 * 保存批量代付订单，并返回主键
	 * 
	 * @author buyi
	 * @date 2017-04-20 09:04:05
	 * @since v1.0.0
	 * @param params
	 * @return
	 * @throws Exception
	 */
	public String savePayoutBatchOrder(PayoutBatchOrderParams params) throws Exception {
		PayoutBatchOrderPO po = new PayoutBatchOrderPO();
		BeanUtils.copyProperties(params, po);
		po.setCurrency(CurrencyEnum.RMB.getValue());
		po.setActPaymentCode(params.getPaymentCode());

		String payoutBatchOrderId = payoutBatchOrderService.saveAndReturnBusiKey(po);

		if (StringUtils.isBlank(payoutBatchOrderId)) {
			throw new YYException(PayRspCodeEnum.COMMON_ERROR_PARAMETER_REQUIRED, "批量代付订单号缺失");
		}

		// 保存详细代付信息
		List<PayoutOrder> dataList = params.getDataList();
		for (PayoutOrder payoutOrder : dataList) {
			PayoutOrderPO payoutOrderPO = new PayoutOrderPO();
			BeanUtils.copyProperties(po, payoutOrderPO);

			BeanUtils.copyProperties(payoutOrder, payoutOrderPO);
			payoutOrderService.saveAndReturnBusiKey(payoutOrderPO);
		}

		return payoutBatchOrderId;
	}

	// /**
	// * 查询代付订单状态
	// *
	// * @author buyi
	// * @date 2017-04-18 18:59:09
	// * @since v1.0.0
	// * @param orderId
	// * @param merchantCode
	// * @return
	// * @throws Exception
	// */
	// public PayoutOrderVO queryPayoutOrder(String orderId, String
	// merchantCode) throws Exception {
	// // 1.查询订单封装VO
	// PayoutOrderVO payoutOrderVO =
	// payoutOrderService.queryPayoutOrderVOByOrderId(orderId, merchantCode);
	// if (payoutOrderVO == null) {
	// return null;
	// }
	//
	// // 2.判断VO是否已关闭, 关闭则直接返回
	// if (payoutOrderVO.isClose()) {
	// logger.info("订单：{}已经关闭", payoutOrderVO.getPayoutOrderId());
	// return payoutOrderVO;
	// }
	//
	// // 3.订单未关闭,但已经代付成功
	// if (payoutOrderVO.getStep(PayoutStepEnum.STEP2_PAY_RESULT) != null) {
	// return payoutOrderVO;
	// }
	//
	// // 4.没有回调记录,但是已经提交代付成功,执行查询
	// if (payoutOrderVO.getStep(PayoutStepEnum.STEP1_SUBMIT_ORDER) != null) {
	// PaymentEnum payment =
	// PaymentEnum.fromValue(payoutOrderVO.getActPaymentCode());
	// ThirdPayService thirdPayService =
	// adapterService.adapterPayService(payment);
	// if (thirdPayService == null) {
	// throw new YYPayException(PayRspCodeEnum.PAY_CODE_ILLEGAL_PAYMENT_CODE,
	// "支付通道:" + payment);
	// }
	// QueryPayoutOrderYYParams params = new QueryPayoutOrderYYParams();
	// params.setMerchantCode(merchantCode);
	// params.setPayoutOrderId(payoutOrderVO.getPayoutOrderId());
	// params.setOrderId(payoutOrderVO.getOrderId());
	// params.setOrderTime(payoutOrderVO.getOrderTime());
	// params.setUserId(payoutOrderVO.getUserId());
	//
	// QueryPayoutOrderYYContent queryPayoutOrder =
	// thirdPayService.queryPayoutOrder(params);
	// // 查询失败
	// if (queryPayoutOrder == null) {
	// throw new YYPayException(PayRspCodeEnum.COMMON_ERR0R_NET_ERROR,
	// "查询第三方代付订单失败:" + orderId);
	// }
	//
	// // 处理中 或 请求超时
	// if
	// (PayRspCodeEnum.PAY_CODE_DEALING.isValue(queryPayoutOrder.getResultCode())
	// ||
	// PayRspCodeEnum.PAY_CODE_REQ_TIME_OUT.isValue(queryPayoutOrder.getResultCode()))
	// {
	// throw new YYPayException(PayRspCodeEnum.COMMON_ERR0R_NET_ERROR,
	// "查询第三方订单结果:" +
	// PayRspCodeEnum.fromValue(queryPayoutOrder.getResultCode()));
	// }
	//
	// YesNoEnum isClose = YesNoEnum.NO;
	//
	// PayoutOrderLogPO logPO = savePayoutOrderLog(payoutOrderVO,
	// PayoutStepEnum.STEP2_PAY_RESULT,
	// queryPayoutOrder.getReqUrl(), queryPayoutOrder.getReqContent(),
	// queryPayoutOrder.getRspContent(),
	// queryPayoutOrder.getSerialNo(), queryPayoutOrder.getResultCode(),
	// queryPayoutOrder.getResultMsg(),
	// isClose, "主动查询");
	//
	// if (StringUtils.isNotBlank(queryPayoutOrder.getSerialNo())) {
	// payoutOrderVO.setSerialNo(queryPayoutOrder.getSerialNo());
	// }
	// payoutOrderVO.setClose(YesNoEnum.YES == isClose);// 设置订单关闭状态
	// payoutOrderVO.getOrderLogPOs().add(logPO);
	//
	// // 插入异步通知任务
	// saveNotifyTask(payoutOrderVO, queryPayoutOrder.getResultCode(),
	// queryPayoutOrder.getResultMsg(),
	// queryPayoutOrder.getSerialNo());
	// }
	//
	// return payoutOrderVO;
	// }

	// /**
	// * 单笔代付异步通知
	// *
	// * @author buyi
	// * @date 2017-04-25 20:32:16
	// * @since v1.0.0
	// * @param task
	// * @return
	// * @throws Exception
	// */
	// @SuppressWarnings("unchecked")
	// public PayoutOrderVO notifyPayoutOrder(NotifyTaskPO task) throws
	// Exception {
	// // 1.查询订单封装VO
	// PayoutOrderVO payoutOrderVO =
	// payoutOrderService.queryPayoutOrderVOByOrderId(task.getOrderId(),
	// task.getMerchantCode());
	// if (payoutOrderVO == null) {
	// return null;
	// }
	// // 2.判断VO是否已关闭, 关闭则直接返回
	// if (payoutOrderVO.isClose()) {
	// return payoutOrderVO;
	// }
	//
	// // 3.订单未关闭,但已经回调成功
	// if (payoutOrderVO.getStep(PayoutStepEnum.STEP3_NOTIFY) != null) {
	// PayoutOrderLogPO logPO = savePayoutOrderLog(payoutOrderVO,
	// PayoutStepEnum.STEP3_NOTIFY, task.getNotifyUrl(),
	// task.getReqContent(), null, null, null, "系统自动关闭订单", YesNoEnum.YES, null);
	// payoutOrderVO.getOrderLogPOs().add(logPO);
	// return payoutOrderVO;
	// }
	//
	// // 4.支付通道已经回调,还未回调商户方
	// if (payoutOrderVO.getStep(PayoutStepEnum.STEP2_PAY_RESULT) != null) {
	// String rspJson = HttpUtil.post(task.getNotifyUrl(),
	// task.getReqContent());
	// if (StringUtils.isBlank(rspJson)) {
	// logger.info("回调失败:{}", task.getOrderId());
	// savePayoutOrderLog(payoutOrderVO, PayoutStepEnum.STEP3_NOTIFY,
	// task.getNotifyUrl(),
	// task.getReqContent(), rspJson, null,
	// PayRspCodeEnum.COMMON_ERR0R_NET_ERROR.getValue(),
	// "请求连接，返回空", YesNoEnum.NO, null);
	// return null;
	// }
	//
	// YYPayRsp<EmptyContent> rsp = JacksonUtil.fromJson(rspJson,
	// YYPayRsp.class, EmptyContent.class);
	// if (rsp == null) {
	// logger.info("回调失败:{} {}", task.getOrderId(), rspJson);
	// savePayoutOrderLog(payoutOrderVO, PayoutStepEnum.STEP3_NOTIFY,
	// task.getNotifyUrl(),
	// task.getReqContent(), rspJson, null,
	// PayRspCodeEnum.PAY_CODE_ILLEGAL_FORMAT_RSP.getValue(),
	// "响应参数不正确", YesNoEnum.NO, null);
	// return null;
	// }
	//
	// YesNoEnum isClose = YesNoEnum.YES;
	// logger.info("回调:{} {}", task.getOrderId(), rspJson);
	//
	// PayoutOrderLogPO logPO = savePayoutOrderLog(payoutOrderVO,
	// PayoutStepEnum.STEP3_NOTIFY, task.getNotifyUrl(),
	// task.getReqContent(), rspJson, null, rsp.getCode(), rsp.getMessage(),
	// isClose, null);
	//
	// payoutOrderVO.setClose(YesNoEnum.YES == isClose);
	// payoutOrderVO.getOrderLogPOs().add(logPO);
	// }
	//
	// return payoutOrderVO;
	// }

	// /**
	// * 发起代付
	// *
	// * @author buyi
	// * @date 2017-04-18 10:38:46
	// * @since v1.0.0
	// * @param payoutOrderId
	// * @throws Exception
	// */
	// public PayoutOrderContent payout(String payoutOrderId, String orderId,
	// String merchantCode) throws Exception {
	// PayoutOrderVO payoutOrderVO =
	// payoutOrderService.queryPayoutOrderVOByOrderId(orderId, merchantCode);
	// if (payoutOrderVO == null) {
	// throw new
	// YYException(PayRspCodeEnum.COMMON_ERROR_OBJECT_NOT_FOUND.getValue(),
	// "订单缺失，payoutOrderId:[" + payoutOrderId + "],merchantCode:[]", "订单不存在");
	// }
	//
	// ThirdPayService thirdPayService = adapterService
	// .adapterPayService(PaymentEnum.fromValue(payoutOrderVO.getActPaymentCode()));
	// PayoutOrderYYParams payoutOrderYYParams = new PayoutOrderYYParams();
	// BeanUtils.copyProperties(payoutOrderVO, payoutOrderYYParams);
	// PayoutOrderYYContent payoutOrderYYContent =
	// thirdPayService.payoutOrder(payoutOrderYYParams);
	//
	// if (payoutOrderYYContent == null) {
	// logger.error("payoutOrderId:{},merchantCode:{}代付失败，响应参数为空",
	// payoutOrderId, merchantCode);
	// throw new
	// YYException(PayRspCodeEnum.COMMON_ERROR_OBJECT_NOT_FOUND.getValue(),
	// "代付响应参数为空", "代付响应参数为空");
	// }
	//
	// // 更新代付订单支付支付模块通知地址
	// PayoutOrderPO payoutOrderPO =
	// payoutOrderService.queryByOrderIdAndMerchantCode(orderId, merchantCode);
	// payoutOrderPO.setPayNotifyUrl(payoutOrderYYContent.getPayNotifyUrl());
	// payoutOrderService.modify(payoutOrderPO);
	//
	// // 保存鉴权日志
	// savePayoutOrderLog(payoutOrderVO, PayoutStepEnum.STEP1_SUBMIT_ORDER,
	// payoutOrderYYContent.getReqUrl(),
	// payoutOrderYYContent.getReqContent(),
	// payoutOrderYYContent.getRspContent(),
	// payoutOrderYYContent.getSerialNo(), payoutOrderYYContent.getResultCode(),
	// payoutOrderYYContent.getResultMsg(), YesNoEnum.NO, null);
	//
	// // 如果订单交易超时，或者订单状态为处理中，则生成主动查询任务
	// if
	// (PayRspCodeEnum.PAY_CODE_REQ_TIME_OUT.isValue(payoutOrderYYContent.getResultCode())
	// ||
	// PayRspCodeEnum.PAY_CODE_DEALING.isValue(payoutOrderYYContent.getResultCode())
	// || PayRspCodeEnum.SUCCESS.isValue(payoutOrderYYContent.getResultCode()))
	// {
	// String startTime = DateUtil
	// .datetime2Str(DateUtil.addMinute(new Date(),
	// payConstants.getPayQueryMinuteDelay()));
	// payCommonService.saveQueryTask(payoutOrderVO.getMerchantCode(),
	// payoutOrderVO.getOrderId(),
	// payoutOrderVO.getSerialNo(), QueryTaskTypeEnum.PAYOUT,
	// payoutOrderVO.getPayoutOrderId(),
	// payoutOrderVO.getActPaymentCode(), startTime, null,
	// payConstants.getQueryTaskMax(), "");
	// }
	//
	// // 封装响应请求参数
	// PayoutOrderContent content = new PayoutOrderContent();
	// BeanUtils.copyProperties(payoutOrderPO, content);
	// content.setPaymentCode(payoutOrderPO.getActPaymentCode());
	// content.setResultCode(payoutOrderYYContent.getResultCode());
	// content.setResultMsg(payoutOrderYYContent.getResultMsg());
	//
	// return content;
	// }

	/**
	 * 发起代付
	 * 
	 * @author buyi
	 * @date 2017-08-11 10:38:46
	 * @since v1.3.0
	 * @param payoutOrderVO
	 * @throws Exception
	 */
	public PayoutOrderContent payout(PayoutOrderVO payoutOrderVO) throws Exception {
		final String op = "PayoutService.payout";

		PayoutOrderPO po = payoutOrderVO.getPayoutOrderPO();

		// 更新代付订单为处理中
		int i = payoutOrderService.updateState(po.getPayoutOrderId(), OrderStateEnum.INI, OrderStateEnum.DEALING, PayExceptionCode.DEALING.getCode(),
				PayExceptionCode.DEALING.getDesc());
		if (i <= 0) {
			// 如果订单状态没有命中，则表示订单已经被处理
			PayoutOrderPO payoutOrderPO = payoutOrderService.queryByIdAndMerchantCode(po.getId(), po.getMerchantCode());
			return PayoutOrderContent.newInstance(payoutOrderPO.getRspCode(), payoutOrderPO.getRspMsg());
		}

		ThirdPayService thirdPayService = adapterService.adapterPayService(PaymentEnum.fromValue(po.getActPaymentCode()));

		PayoutOrderYYParams payoutOrderYYParams = new PayoutOrderYYParams();
		payoutOrderYYParams.setPayoutOrderId(po.getPayoutOrderId());
		payoutOrderYYParams.setOrderId(po.getOrderId());
		payoutOrderYYParams.setMerchantCode(po.getMerchantCode());
		payoutOrderYYParams.setUserId(po.getUserId());
		// payoutOrderYYParams.setOrderTime(po.getOrderTime());
		payoutOrderYYParams.setPayOrderTime(po.getCreateTime());
		payoutOrderYYParams.setPayeeCardNo(CryptUtil.decrypt(po.getPayeeCardNoCip()));
		payoutOrderYYParams.setPayeeName(po.getPayeeName());
		payoutOrderYYParams.setAmount(po.getAmount());

		// 修改代付入口，edit by buyi since 2.1.5
		// PayoutOrderYYContent payoutOrderYYContent = thirdPayService.payoutOrder(payoutOrderYYParams);
		// if (payoutOrderYYContent == null) {
		// logger.error("payoutOrderId:{},merchantCode:{}代付失败，响应参数为空", po.getPayoutOrderId(), po.getMerchantCode());
		// throw new YYException(PayRspCodeEnum.COMMON_ERROR_OBJECT_NOT_FOUND.getValue(), "代付响应参数为空", "代付响应参数为空");
		// }
		// 保存代付日志
		// savePayoutOrderLog(po, PayoutStepEnum.STEP_SUBMIT_ORDER, payoutOrderYYContent.getReqUrl(), payoutOrderYYContent.getReqContent(),
		// payoutOrderYYContent.getRspContent(), payoutOrderYYContent.getSerialNo(), payoutOrderYYContent.getResultCode(),
		// payoutOrderYYContent.getResultMsg(), YesNoEnum.NO, null);

		// 封装响应请求参数
		// PayoutOrderContent content = new PayoutOrderContent();
		// content.setResultCode(payoutOrderYYContent.getResultCode());
		// content.setResultMsg(payoutOrderYYContent.getResultMsg());

		// return content;
		PayoutDataBinder binder = thirdPayService.payoutOderComposite(payoutOrderYYParams);
		// 更新代付订单状态
		int updateState = payoutOrderService.updateState(po.getPayoutOrderId(), OrderStateEnum.DEALING, binder.getState(), binder.getResultCode(),
				binder.getResultMsg());
		if (updateState <= 0) {
			// 如果更新结果还没有命中，则异常。（更新不命中的情况，基本上不存在的）
			logger.error(Log.op(op).msg("更新代付结果结果状态没有命中").kv("payoutOrderId", po.getPayoutOrderId())
					.kv("origState", OrderStateEnum.DEALING.getValue()).kv("destState", binder.getState().getValue()).toString());
			throw PayExceptionCode.WARN_UNKNOWN.exp();
		}

		// 保存代付日志
		// savePayoutOrderLog(po, PayoutStepEnum.STEP_SUBMIT_ORDER, binder.getReqUrl(), binder.getReqContent(), binder.getRspContent(),
		// binder.getSerialNo(), binder.getResultCode(), binder.getResultMsg(), YesNoEnum.NO, null);

		return PayoutOrderContent.newInstance(binder.getResultCode(), binder.getResultMsg());
		// 代付，暂时不设置自动查询机制
		// 如果订单交易超时，或者订单状态为处理中，则生成主动查询任务
		// if
		// (PayRspCodeEnum.PAY_CODE_REQ_TIME_OUT.isValue(payoutOrderYYContent.getResultCode())
		// ||
		// PayRspCodeEnum.PAY_CODE_DEALING.isValue(payoutOrderYYContent.getResultCode())
		// ||
		// PayRspCodeEnum.SUCCESS.isValue(payoutOrderYYContent.getResultCode()))
		// {
		// String startTime = DateUtil
		// .datetime2Str(DateUtil.addMinute(new Date(),
		// payConstants.getPayQueryMinuteDelay()));
		// payCommonService.saveQueryTask(payoutOrderVO.getMerchantCode(),
		// payoutOrderVO.getOrderId(),
		// payoutOrderVO.getSerialNo(), QueryTaskTypeEnum.PAYOUT,
		// payoutOrderVO.getPayoutOrderId(),
		// payoutOrderVO.getActPaymentCode(), startTime, null,
		// payConstants.getQueryTaskMax(), "");
		// }

	}

	/**
	 * 发起批量代付请求
	 * 
	 * @author buyi
	 * @throws Exception
	 * @date 2017-04-20 10:14:41
	 * @since v1.0.0
	 */
	public YYFaxRsp<PayoutOrderContent> payoutBatch(PayoutBatchOrderParams payoutBatchOrderParams) throws Exception {
		// 持久化代付订单
		savePayoutBatchOrder(payoutBatchOrderParams);

		String merchantCode = payoutBatchOrderParams.getMerchantCode();
		String orderId = payoutBatchOrderParams.getOrderId();

		YYFaxRsp<PayoutOrderContent> rsp = new YYFaxRsp<>(PayRspCodeEnum.SUCCESS);

		PayoutBatchOrderVO payoutBatchOrderVo = payoutBatchOrderService.queryPayoutBatchOrderVO(merchantCode, orderId);

		ThirdPayService service = adapterService.adapterPayService(PaymentEnum.fromValue(payoutBatchOrderVo.getActPaymentCode()));
		if (service == null) {
			rsp.setRsp(PayRspCodeEnum.PAY_CODE_PAYMENT_CODE_NOT_HIT);
			rsp.setMessage("没有找到相关支付通道服务");
			return rsp;
		}

		PayoutBatchOrderYYParams params = new PayoutBatchOrderYYParams();
		BeanUtils.copyProperties(payoutBatchOrderVo, params);

		List<PayoutOrderYY> dataList = new ArrayList<PayoutOrderYY>();

		List<PayoutOrderVO> payoutOrderVOs = payoutBatchOrderVo.getPayoutOrderVOs();
		if (payoutOrderVOs != null) {
			for (PayoutOrderVO payoutOrderVO : payoutOrderVOs) {
				PayoutOrderYY payoutOrderYY = new PayoutOrderYY();
				BeanUtils.copyProperties(payoutOrderVO, payoutOrderYY);
				dataList.add(payoutOrderYY);
			}
		}

		params.setDataList(dataList);

		PayoutBatchOrderYYContent payoutBatchOrderYYContent = service.payoutBatchOrder(params);

		// 写入批量代付日志
		savePayoutBatchOrderLog(payoutBatchOrderVo, PayoutBatchStepEnum.STEP1_SUBMIT_ORDER, payoutBatchOrderYYContent.getReqUrl(),
				payoutBatchOrderYYContent.getReqContent(), payoutBatchOrderYYContent.getRspContent(), payoutBatchOrderYYContent.getResultCode(),
				payoutBatchOrderYYContent.getResultMsg(), YesNoEnum.NO, null);

		// 批量代付查询任务： 主动查询
		String startTime = DateUtil.datetime2Str(DateUtil.addMinute(new Date(), payConstants.getPayoutBatchQueryMinuteDelay())); // 默认为15分钟
		payCommonService.saveQueryTask(merchantCode, orderId, null, QueryTaskTypeEnum.PAYOUT_BATCH, payoutBatchOrderVo.getPayoutBatchOrderId(),
				payoutBatchOrderVo.getActPaymentCode(), startTime, null, payConstants.getQueryTaskMax(), "");

		// 批量代付查询任务： 对账查询
		String startTimeReconciliation = DateUtil.datetime2Str(DateUtil.set(DateUtil.addDay(new Date(), payConstants.getPayoutBatchCheckDayDelay()),
				payConstants.getPayoutBatchCheckHour(), payConstants.getPayoutBatchCheckMinute(), payConstants.getPayoutBatchCheckSecond())); // 设置次日9点
		payCommonService.saveQueryTask(merchantCode, orderId, null, QueryTaskTypeEnum.PAYOUT_BATCH_RECONCILIATION,
				payoutBatchOrderVo.getPayoutBatchOrderId(), payoutBatchOrderVo.getActPaymentCode(), startTimeReconciliation, null,
				payConstants.getQueryTaskMax(), "");

		PayoutOrderContent content = new PayoutOrderContent();
		BeanUtils.copyProperties(payoutBatchOrderVo, content);
		content.setResultCode(payoutBatchOrderYYContent.getResultCode());
		content.setResultMsg(payoutBatchOrderYYContent.getResultMsg());

		rsp.setContent(content);

		return rsp;
	}

	/**
	 * 保存支付日志
	 * 
	 * @author buyi
	 * @date 2017-04-17 17:31:44
	 * @since v1.0.0
	 * @param payoutOrderPO
	 * @param step
	 * @param reqUrl
	 * @param reqContent
	 * @param rspContent
	 * @param serialNo
	 * @param resultCode
	 * @param resultMsg
	 * @param isClose
	 * @throws Exception
	 */
	public PayoutOrderLogPO savePayoutOrderLog(PayoutOrderPO payoutOrderPO, PayoutStepEnum step, String reqUrl, String reqContent, String rspContent,
			String serialNo, Integer resultCode, String resultMsg, YesNoEnum isClose, String remark) throws Exception {
		PayoutOrderLogPO logPO = new PayoutOrderLogPO();
		BeanUtils.copyProperties(payoutOrderPO, logPO);
		logPO.setPaymentCode(payoutOrderPO.getActPaymentCode());

		logPO.setStep(step.getValue());
		logPO.setReqUrl(reqUrl);
		logPO.setReqContent(reqContent);
		logPO.setRspContent(rspContent);
		logPO.setSerialNo(serialNo);
		logPO.setResultCode(resultCode);
		logPO.setResultMsg(resultMsg);
		logPO.setClosed(isClose.getValue());
		logPO.setRemark(remark);
		payoutOrderLogService.save(logPO);

		return logPO;
	}

	private PayoutBatchOrderLogPO savePayoutBatchOrderLog(PayoutBatchOrderVO payoutBatchOrderVO, PayoutBatchStepEnum step, String reqUrl,
			String reqContent, String rspContent, Integer resultCode, String resultMsg, YesNoEnum isClose, String remark) throws Exception {
		PayoutBatchOrderLogPO logPO = new PayoutBatchOrderLogPO();
		BeanUtils.copyProperties(payoutBatchOrderVO, logPO);
		logPO.setPaymentCode(payoutBatchOrderVO.getActPaymentCode());

		logPO.setStep(step.getValue());
		logPO.setReqUrl(reqUrl);
		logPO.setReqContent(reqContent);
		logPO.setRspContent(rspContent);
		logPO.setResultCode(resultCode);
		logPO.setResultMsg(resultMsg);
		logPO.setClosed(isClose.getValue());
		logPO.setRemark(remark);
		payoutBatchOrderLogService.save(logPO);

		return logPO;
	}

	/**
	 * 向第三方通道查询订单,并将查询结果更新到本地
	 * 
	 * @author jiangmy
	 * @date 2017-04-18 09:02:01
	 * @since v1.0.0
	 * @param orderId
	 * @param merchantCode
	 * @throws Exception
	 */
	public PayoutBatchOrderVO queryPayoutBatchOrder(String orderId, String merchantCode) throws Exception {
		// 1.查询订单封装VO
		PayoutBatchOrderVO payoutBatchOrderVO = payoutBatchOrderService.queryPayoutBatchOrderVO(merchantCode, orderId);
		if (payoutBatchOrderVO == null) {
			return null;
		}
		// 2.判断VO是否已关闭, 关闭则直接返回
		if (payoutBatchOrderVO.isClose()) {
			return payoutBatchOrderVO;
		}
		// 3.订单未关闭,但已经支付成功
		if (payoutBatchOrderVO.getStep(PayoutBatchStepEnum.STEP2_PAY_RESULT) != null) {
			return payoutBatchOrderVO;
		}

		// 4.没有主动查询记录,但是已经受理成功,执行查询
		if (payoutBatchOrderVO.getStep(PayoutBatchStepEnum.STEP1_SUBMIT_ORDER) != null) {

			PaymentEnum payment = PaymentEnum.fromValue(payoutBatchOrderVO.getPaymentCode());
			ThirdPayService thirdPayService = adapterService.adapterPayService(payment);
			if (thirdPayService == null) {
				throw new YYPayException(PayRspCodeEnum.PAY_CODE_ILLEGAL_PAYMENT_CODE, "支付通道:" + payment);
			}

			QueryBatchPayoutOrderYYParams params = new QueryBatchPayoutOrderYYParams();
			params.setMerchantCode(merchantCode);
			params.setOrderId(payoutBatchOrderVO.getOrderId());
			params.setBatchDate(payoutBatchOrderVO.getBatchDate());
			params.setBatchNo(payoutBatchOrderVO.getBatchNo());

			QueryBatchPayoutOrderYYContent queryContent = thirdPayService.queryBatchPayoutOrder(params);

			// 查询失败
			if (queryContent == null) {
				throw new YYPayException(PayRspCodeEnum.COMMON_ERR0R_NET_ERROR, "查询第三方订单失败:" + orderId);
			}

			// 处理中 或 请求超时
			if (PayRspCodeEnum.PAY_CODE_DEALING.isValue(queryContent.getResultCode())
					|| PayRspCodeEnum.PAY_CODE_REQ_TIME_OUT.isValue(queryContent.getResultCode())) {
				throw new YYPayException(PayRspCodeEnum.COMMON_ERR0R_NET_ERROR,
						"查询第三方订单结果:" + PayRspCodeEnum.fromValue(queryContent.getResultCode()));
			}

			// 更新批量订单结果信息
			YesNoEnum childPayoutOrderIsClose = YesNoEnum.NO;
			modifyPayoutBatchOrder(payoutBatchOrderVO, queryContent, PayoutBatchStepEnum.STEP2_PAY_RESULT, "主动查询", childPayoutOrderIsClose);

			// 主动查询结束，生成异步通知
			createPayoutBatchResultNotify(payoutBatchOrderVO);
		}

		return payoutBatchOrderVO;
	}

	/**
	 * 查询对账结果
	 * 
	 * @author buyi
	 * @date 2017-04-21 17:44:09
	 * @since v1.0.0
	 * @param orderId
	 * @param merchantCode
	 * @return
	 * @throws Exception
	 */
	public PayoutBatchOrderVO queryBatchPayoutOrderCheck(String orderId, String merchantCode) throws Exception {
		// 1.查询订单封装VO
		PayoutBatchOrderVO payoutBatchOrderVO = payoutBatchOrderService.queryPayoutBatchOrderVO(merchantCode, orderId);
		if (payoutBatchOrderVO == null) {
			return null;
		}
		// 2.判断VO是否已关闭, 关闭则直接返回
		if (payoutBatchOrderVO.isClose()) {
			return payoutBatchOrderVO;
		}
		// 3.订单未关闭,但已经支付成功
		if (payoutBatchOrderVO.getStep(PayoutBatchStepEnum.STEP3_CHECK_RESULT) != null) {
			return payoutBatchOrderVO;
		}

		// 4.没有主动查询记录,但是已经受理成功,执行查询
		if (payoutBatchOrderVO.getStep(PayoutBatchStepEnum.STEP1_SUBMIT_ORDER) != null) {

			PaymentEnum payment = PaymentEnum.fromValue(payoutBatchOrderVO.getPaymentCode());
			ThirdPayService thirdPayService = adapterService.adapterPayService(payment);
			if (thirdPayService == null) {
				throw new YYPayException(PayRspCodeEnum.PAY_CODE_ILLEGAL_PAYMENT_CODE, "支付通道:" + payment);
			}

			QueryBatchPayoutOrderYYParams params = new QueryBatchPayoutOrderYYParams();
			params.setMerchantCode(merchantCode);
			params.setOrderId(payoutBatchOrderVO.getOrderId());
			params.setBatchDate(payoutBatchOrderVO.getBatchDate());
			params.setBatchNo(payoutBatchOrderVO.getBatchNo());

			QueryBatchPayoutOrderYYContent queryContent = thirdPayService.queryBatchPayoutOrder(params);

			// 查询失败
			if (queryContent == null) {
				throw new YYPayException(PayRspCodeEnum.COMMON_ERR0R_NET_ERROR, "查询第三方订单失败:" + orderId);
			}

			// 处理中 或 请求超时
			if (PayRspCodeEnum.PAY_CODE_DEALING.isValue(queryContent.getResultCode())
					|| PayRspCodeEnum.PAY_CODE_REQ_TIME_OUT.isValue(queryContent.getResultCode())) {
				throw new YYPayException(PayRspCodeEnum.COMMON_ERR0R_NET_ERROR,
						"查询第三方订单结果:" + PayRspCodeEnum.fromValue(queryContent.getResultCode()));
			}

			// 更新批量订单结果信息，并关闭详细代付订单
			YesNoEnum childPayoutOrderIsClose = YesNoEnum.YES;
			modifyPayoutBatchOrder(payoutBatchOrderVO, queryContent, PayoutBatchStepEnum.STEP3_CHECK_RESULT, "对账查询", childPayoutOrderIsClose);
		}

		return payoutBatchOrderVO;
	}

	/**
	 * 更新批量代付信息
	 * 
	 * @author buyi
	 * @date 2017-04-22 13:34:58
	 * @since v1.0.0
	 * @param payoutBatchOrderVO
	 * @param queryContent
	 * @param step
	 * @param remark
	 * @param childOderClose
	 * @params childOderClose 代付订单关闭状态
	 * @throws Exception
	 */
	private void modifyPayoutBatchOrder(PayoutBatchOrderVO payoutBatchOrderVO, QueryBatchPayoutOrderYYContent queryContent, PayoutBatchStepEnum step,
			String remark, YesNoEnum childOderClose) throws Exception {
		YesNoEnum isClose = YesNoEnum.NO;

		// 更新批量代付结果信息
		payoutBatchOrderVO.setResultCode(queryContent.getResultCode());
		payoutBatchOrderVO.setResultMsg(queryContent.getResultMsg());
		payoutBatchOrderVO.setSuccessCount(queryContent.getSuccessCount());
		payoutBatchOrderVO.setSuccessAmount(queryContent.getSuccessAmount());
		payoutBatchOrderVO.setFailCount(queryContent.getFailCount());
		payoutBatchOrderVO.setFailAmount(queryContent.getFailAmount());
		payoutBatchOrderVO.setUnknownCount(queryContent.getUnknownCount());
		payoutBatchOrderVO.setUnknownAmount(queryContent.getUnknownAmount());

		PayoutBatchOrderPO payoutBatchOrderPO = new PayoutBatchOrderPO();
		BeanUtils.copyProperties(payoutBatchOrderVO, payoutBatchOrderPO);
		payoutBatchOrderService.modify(payoutBatchOrderPO);

		// 保存批量代付日志
		PayoutBatchOrderLogPO payoutBatchOrderLogPO = savePayoutBatchOrderLog(payoutBatchOrderVO, step, queryContent.getReqUrl(),
				queryContent.getReqContent(), queryContent.getRspContent(), queryContent.getResultCode(), queryContent.getResultMsg(), isClose,
				remark);

		// 更新批量代付快照信息
		payoutBatchOrderVO.getPayoutBatchOrderLogPOs().add(payoutBatchOrderLogPO);
		payoutBatchOrderVO.setClose(YesNoEnum.YES == isClose); // 设置订单关闭状态

		// 保存详细代付订单日志
		List<QueryPayoutOrder> queryPayoutOrders = queryContent.getQueryPayoutOrders();
		if (queryPayoutOrders != null) {
			for (QueryPayoutOrder queryPayoutOrder : queryPayoutOrders) {
				PayoutOrderVO payoutOrderVO = payoutBatchOrderVO.getPayoutOrderVO(queryPayoutOrder.getUserId());
				// payoutOrderVO.setSerialNo(queryPayoutOrder.getSerialNo());
				// payoutOrderVO.setClose(YesNoEnum.YES == childOderClose);
				// 插入日志
				PayoutOrderLogPO payoutOrderLogPO = savePayoutOrderLog(payoutOrderVO.getPayoutOrderPO(), PayoutStepEnum.STEP_PAY_RESULT, null, null,
						null, queryPayoutOrder.getSerialNo(), queryPayoutOrder.getResultCode(), queryPayoutOrder.getResultMsg(), childOderClose,
						"批量代付结果查询");

				// 更新代付快照信息
				payoutOrderVO.getOrderLogPOs().add(payoutOrderLogPO);
			}
		}
	}

	/**
	 * 解析单笔代付异步回调
	 * 
	 * @author buyi
	 * @date 2017-04-20 17:46:25
	 * @since v1.0.0
	 * @param paymentEnum
	 *        支付通道枚举
	 * @param reque
	 * @return
	 * @throws Exception
	 */
	// public String processResultNotify(String paymentCode, OrderNotifyContent
	// notifyContent) throws Exception {
	// // 获取订单信息
	// PayBusiIdVO payOrderIdVO =
	// payoutOrderService.resolverPayoutOrderId(notifyContent.getPayOrderId());
	//
	// PayoutOrderVO payoutOrderVO =
	// payoutOrderService.queryPayoutOrderVOByOrderId(payOrderIdVO.getOrderId(),
	// payOrderIdVO.getMerchantCode());
	// if (payoutOrderVO == null) {
	// logger.error("数据库订单缺失，payoutOrderId:{},merchantCode:{}",
	// notifyContent.getPayOrderId(),
	// payOrderIdVO.getMerchantCode());
	// return null;
	// }
	//
	// // TODO 如果金额不一致，发出预警
	// if (!payoutOrderVO.getAmount().equals(notifyContent.getAmount())) {
	// logger.error("支付金额：" + payoutOrderVO.getAmount() + "，同步回调金额：" +
	// notifyContent.getAmount() + "不一致");
	// }
	//
	// // 判断订单状态是否关闭
	// if (payoutOrderVO.isClose()) { // 如果订单已经结束，则不做任何操作
	// logger.info("代付订单：{}已经关闭，不做任何操作", notifyContent.getPayOrderId());
	// return notifyContent.getRspContent();
	// }
	//
	// // 写入日志
	// savePayoutOrderLog(payoutOrderVO, PayoutStepEnum.STEP2_PAY_RESULT,
	// payoutOrderVO.getPayNotifyUrl(),
	// notifyContent.getReqContent(), notifyContent.getRspContent(),
	// notifyContent.getSerialNo(),
	// notifyContent.getResultCode(), notifyContent.getResultMsg(),
	// YesNoEnum.YES, null);
	//
	// // 插入异步通知日志
	// saveNotifyTask(payoutOrderVO, notifyContent.getResultCode(),
	// notifyContent.getResultMsg(),
	// notifyContent.getSerialNo());
	//
	// return notifyContent.getRspContent();
	// }

	/**
	 * 生成批量代付异步通知
	 * 
	 * @author buyi
	 * @date 2017-04-22 15:39:51
	 * @since v1.0.0
	 * @param vo
	 * @throws Exception
	 */
	private void createPayoutBatchResultNotify(PayoutBatchOrderVO vo) throws Exception {
		// 获取商户信息
		MerchantConfigPO merchantConfigPO = merchantConfigService.queryByMerchantCode(vo.getMerchantCode());

		// 封装异步通知消息
		PayoutBatchResultNotifyParams payoutBatchResultNotifyParams = new PayoutBatchResultNotifyParams();

		PayoutBatchResultNotify params = new PayoutBatchResultNotify();
		params.setResultCode(vo.getResultCode());
		params.setResultMsg(vo.getResultMsg());
		params.setMerchantCode(vo.getMerchantCode());
		params.setPaymentCode(vo.getPaymentCode());
		params.setOrderId(vo.getOrderId());
		params.setBatchDate(vo.getBatchDate());
		params.setBatchNo(vo.getBatchNo());
		params.setSuccessCount(vo.getSuccessCount());
		params.setSuccessAmount(vo.getSuccessAmount());
		params.setFailCount(vo.getFailCount());
		params.setFailAmount(vo.getFailAmount());
		params.setUnknownCount(vo.getUnknownCount());
		params.setUnknownAmount(vo.getUnknownAmount());

		List<PayoutOrderVO> payoutOrderVOs = vo.getPayoutOrderVOs();

		List<PayoutResultNotify> dataList = new ArrayList<PayoutResultNotify>();

		if (payoutOrderVOs != null) {
			for (PayoutOrderVO payoutOrderVO : payoutOrderVOs) {
				PayoutResultNotify payoutResultNotify = new PayoutResultNotify();
				// payoutResultNotify.setOrderId(payoutOrderVO.getOrderId());
				// payoutResultNotify.setUserId(payoutOrderVO.getUserId());
				// payoutResultNotify.setPayeeCardNo(payoutOrderVO.getPayeeCardNo());
				// payoutResultNotify.setPayeeName(payoutOrderVO.getPayeeName());
				// payoutResultNotify.setAmount(payoutOrderVO.getAmount());
				// payoutResultNotify.setSerialNo(payoutOrderVO.getSerialNo());
				// payoutResultNotify.setResultCode(payoutOrderVO.getResultCode());
				// payoutResultNotify.setResultMsg(payoutOrderVO.getResultMsg());
				BeanUtils.copyProperties(payoutOrderVO, payoutResultNotify);
				payoutResultNotify.setSign(payoutResultNotify.sign(merchantConfigPO.getSignKey()));

				dataList.add(payoutResultNotify);
			}
		}

		params.setDataList(dataList);

		payoutBatchResultNotifyParams.setSign(params.sign(merchantConfigPO.getSignKey()));
		payoutBatchResultNotifyParams.setParams(params);

		// 插入异步通知日志
		payCommonService.saveNotifyTask(vo.getMerchantCode(), vo.getOrderId(), null, NotifyTaskTypeEnum.PAYOUT_BATCH, vo.getPayoutBatchOrderId(),
				vo.getNotifyUrl(), JacksonUtil.noemptyMapper.toJson(payoutBatchResultNotifyParams), DateUtil.datetime2Str(new Date()), null,
				payConstants.getMaxNo(), "");

	}

	/**
	 * 查询代付结果
	 *
	 * @author wujiande
	 * @date 2018/5/11 23:47
	 * @since v2.1.5
	 * @param orderId
	 * @param merchantCode
	 * @return
	 * @throws Exception
	 */
	public QueryPayoutOrderContent queryPayoutOrder(String orderId, String merchantCode) throws Exception {
		// 查询代付订单
		PayoutOrderPO po = payoutOrderService.queryByOrderIdAndMerchantCode(orderId, merchantCode);

		// 检查是否可以直接返回
		QueryPayoutOrderContent content = checkOrderForQuery(po, orderId, merchantCode);
		if (content != null) {
			return content;
		}

		// 查询代付结果
		ThirdPayService thirdPayService = adapterService.adapterPayService(PaymentEnum.fromValue(po.getActPaymentCode()));
		QueryPayoutOrderYYParams payoutOrderYYParams = buildQueryPayoutOrderYYParams(po);
		QueryPayoutOrderYYContent payoutOrderYYContent = thirdPayService.queryPayoutOrder(payoutOrderYYParams);

		// 检查响应结果
		content = checkContentForQuery(payoutOrderYYContent, po);
		if (content != null) {
			return content;
		}

		// 更新状态
		updatePayoutOrderState(po.getPayoutOrderId(), payoutOrderYYContent);

		// 保存代付日志
		// savePayoutOrderLog(po, PayoutStepEnum.STEP_QUERY, payoutOrderYYContent.getReqUrl(), payoutOrderYYContent.getReqContent(),
		// payoutOrderYYContent.getRspContent(), payoutOrderYYContent.getSerialNo(), payoutOrderYYContent.getResultCode(),
		// payoutOrderYYContent.getResultMsg(), YesNoEnum.NO, null);
		return buildQueryPayoutOrderContent(po, payoutOrderYYContent);
	}

	/**
	 * 检查查询代付结果的响应结果
	 *
	 * @author wujiande
	 * @date 2018/5/11 22:51
	 * @since v2.1.5
	 * @param payoutOrderYYContent
	 * @param po
	 * @return
	 */
	private QueryPayoutOrderContent checkContentForQuery(QueryPayoutOrderYYContent payoutOrderYYContent, PayoutOrderPO po) {
		final String op = "PayoutService.checkContentForQuery";
		QueryPayoutOrderContent content = null;
		if (payoutOrderYYContent == null) {
			logger.error(Log.op(op).msg("查询代付失败，响应参数为空").kv("orderId", po.getOrderId()).kv("merchantCode", po.getMerchantCode()).toString());
			content = new QueryPayoutOrderContent();
			copyPayoutOrderPoProperties(content, po);
			content.setResultCode(PayRspCodeEnum.COMMON_ERROR_OBJECT_NOT_FOUND.getValue().toString());
			content.setResultMsg("查询代付响应参数为空");
		}
		return content;
	}

	/**
	 * 根据查询代付订单响应结果更新状态
	 *
	 * @author wujiande
	 * @date 2018/5/11 23:28
	 * @since v2.1.5
	 * @param payoutOrderId
	 * @param content
	 * @return
	 */
	private void updatePayoutOrderState(String payoutOrderId, QueryPayoutOrderYYContent content) {
		// TODO 由于时间原因，该处获取状态没复用代码，二期重构需优化
		OrderStateEnum state = getQueryPayoutOrderState(content.getResultCode());
		payoutOrderService.updateStateByPayoutOrderId(payoutOrderId, state.getValue(), content.getResultCode(), content.getResultMsg());
	}

	/**
	 * 获取查询代付的订单状态
	 * (该处使用 {@link com.yyfax.pay.third.model.to.yyfax.DataBinder#getState}的代码, 二期重构需优化该处代码 )
	 *
	 * @author wujiande
	 * @date 2018-05-17 10:14:28
	 * @since v2.1.5
	 * @param resultCode
	 * @return
	 */
	private OrderStateEnum getQueryPayoutOrderState(Integer resultCode) {
		if (PayExceptionCode.SUCCESS.isCode(resultCode)) {
			// 如果响应码为成功，则返回state为成功
			return OrderStateEnum.SUCCESS;
		}

		if (PayExceptionCode.isTimeout(resultCode)) {
			// 如果响应码为超时，则返回超时状态
			return OrderStateEnum.TIMEOUT;
		}

		if (PayExceptionCode.isToConfirm(resultCode)) {
			// 如果响应码为待确认类型的，则返回待确认状态
			return OrderStateEnum.TOCONFIRM;
		}

		// 其他情况，则默认返回失败
		return OrderStateEnum.FAIL;
	}

	/**
	 * 构建查询代付订单请求参数
	 *
	 * @author wujiande
	 * @date 2018/5/11 23:28
	 * @since v2.1.5
	 * @param po
	 * @return 查询代付订单请求参数
	 */
	private QueryPayoutOrderYYParams buildQueryPayoutOrderYYParams(PayoutOrderPO po) {
		QueryPayoutOrderYYParams payoutOrderYYParams = new QueryPayoutOrderYYParams();
		payoutOrderYYParams.setPayoutOrderId(po.getPayoutOrderId());
		payoutOrderYYParams.setOrderId(po.getOrderId());
		payoutOrderYYParams.setMerchantCode(po.getMerchantCode());
		payoutOrderYYParams.setUserId(po.getUserId());
		payoutOrderYYParams.setOrderTime(po.getOrderTime());
		payoutOrderYYParams.setCreateTime(po.getCreateTime());
		return payoutOrderYYParams;
	}

	/**
	 * 检查订单状态
	 * 
	 * @author wujiande
	 * @date 2018/5/11 22:51
	 * @since v2.1.5
	 * @param po
	 * @param orderId
	 * @param merchantCode
	 * @return
	 */
	private QueryPayoutOrderContent checkOrderForQuery(PayoutOrderPO po, String orderId, String merchantCode) {
		final String op = "PayoutService.checkOrder";
		QueryPayoutOrderContent content = new QueryPayoutOrderContent();
		if (po == null) {
			logger.error(Log.op(op).msg("【代付】查询订单不存在").kv("orderId", orderId).kv("merchantCode", merchantCode).toString());
			throw new YYException(PayRspCodeEnum.PAY_CODE_ORDER_NOT_FOUND);
		}
		if (OrderStateEnum.FAIL.isValue(po.getState()) || OrderStateEnum.SUCCESS.isValue(po.getState())) {
			copyPayoutOrderPoProperties(content, po);
			content.setResultCode(Integer.toString(po.getRspCode()));
			content.setResultMsg(po.getRspMsg());
			return content;
		}
		return null;
	}

	/**
	 * 构建查询代付订单响应结果
	 *
	 * @author wujiande
	 * @date 2018/5/12 0:25
	 * @since v2.1.5
	 * @param po
	 * @param payoutOrderYYContent
	 * @return
	 */
	private QueryPayoutOrderContent buildQueryPayoutOrderContent(PayoutOrderPO po, QueryPayoutOrderYYContent payoutOrderYYContent) {
		QueryPayoutOrderContent content = new QueryPayoutOrderContent();
		copyPayoutOrderPoProperties(content, po);
		content.setResultCode(Integer.toString(payoutOrderYYContent.getResultCode()));
		content.setResultMsg(payoutOrderYYContent.getResultMsg());
		return content;
	}

	/**
	 * 拷贝代付订单信息到查询代付结果响应参数
	 *
	 * @author wujiande
	 * @date 2018/5/14 16:35
	 * @since v2.1.5
	 * @param content 查询代付结果响应参数
	 * @param po 代付订单
	 */
	private void copyPayoutOrderPoProperties(QueryPayoutOrderContent content, PayoutOrderPO po) {
		content.setUserId(po.getUserId());
		content.setOrderId(po.getOrderId());
		content.setMerchantCode(po.getMerchantCode());
		content.setPaymentCode(po.getPaymentCode());
		content.setAmount(po.getAmount());
	}

	/**
	 * 处理退票逻辑<br>
	 * 如果异常，则抛出异常事务回滚
	 * 
	 * @author buyi
	 * @date 2018-05-23 16:13:20
	 * @since v2.1.5
	 * @param binder
	 * @return
	 * @throws Exception
	 */
	public void processRefundNotify(PayoutRefundDataBinder binder) throws Exception {
		final String op = "PayoutService.processRefundNotify";

		PayoutOrderPO po = payoutOrderService.queryByPayoutOrderId(binder.getBusiId());
		if (po == null) {
			// 如果订单不存在，则预警
			logger.error(
					Log.op(op).msg("代付退票处理异常，找不到订单").kv("payoutOrderId", binder.getBusiId()).kv("merchantCode", binder.getMerchantCode()).toString());

			return;
		}

		// 判断订单已经产生退票通知则不再进行
		if (YesNoEnum.YES.isValue(po.getIsRefund())) {
			logger.info(Log.op(op).msg("代付已经产生过退票，订单不再处理").kv("payoutOrderId", binder.getBusiId()).toString());
			return;
		}

		// 更新该订单状态
		int updateState = payoutOrderService.updateRefundState(po.getPayoutOrderId(), OrderStateEnum.FAIL, PayExceptionCode.ERROR_REFUND.getCode(),
				PayExceptionCode.ERROR_REFUND.getDesc(), YesNoEnum.NO.getValue(), YesNoEnum.YES.getValue());

		if (updateState <= 0) {
			// 更新没有命中则直接返回
			logger.warn(Log.op(op).msg("代付退票，更新订单状态失败").kv("orgiState", po.getState()).kv("destState", OrderStateEnum.FAIL.getValue())
					.kv("payoutOrderId", binder.getBusiId()).toString());
			return;
		}

		// 插入退票异步通知日志
		saveRefundNotifyTask(po);

		return;
	}

	/**
	 * 保存退票异步通知任务
	 * 
	 * @author buyi
	 * @date 2018-05-23 16:29:14
	 * @since v1.0.0
	 * @param po
	 * @param resultCode
	 * @param resultMsg
	 */
	private void saveRefundNotifyTask(PayoutOrderPO po) {
		final String op = "PayoutService.saveRefundNotifyTask";
		try {
			// 获取商户信息
			MerchantConfigPO merchantConfigPO = merchantConfigService.queryByMerchantCode(po.getMerchantCode());
			if (merchantConfigPO == null) {
				throw new YYException(PayRspCodeEnum.PAY_CODE_MERCHANT_NOT_EXISTS, "商户：" + po.getMerchantCode() + "信息不存在");
			}

			// 封装异步通知消息
			PayoutResultNotifyParams resultNotifyParams = new PayoutResultNotifyParams();
			PayoutNotifyParams notifyParams = new PayoutNotifyParams();
			notifyParams.setResultCode(PayExceptionCode.SUCCESS.getCode());
			notifyParams.setResultMsg("退票");
			notifyParams.setOrderId(po.getOrderId());
			notifyParams.setUserId(po.getUserId());

			resultNotifyParams.setMerchantCode(po.getMerchantCode());
			resultNotifyParams.setSign(CheckSignUtils.sign2(notifyParams, merchantConfigPO.getSignKey()));
			resultNotifyParams.setParams(notifyParams);

			// 插入异步通知日志
			payCommonService.saveNotifyTask(po.getMerchantCode(), po.getOrderId(), "", NotifyTaskTypeEnum.PAYOUT_REFUND, po.getPayoutOrderId(),
					po.getRefundUrl(), JacksonUtil.noemptyMapper.toJson(resultNotifyParams), DateUtil.datetime2Str(new Date()), null,
					payConstants.getMaxNo(), "");
		} catch (Exception e) {
			logger.error(Log.op(op).msg("代付退票保存异步通知任务异常").kv("payoutOrderId", po.getPayoutOrderId()).toString(), e);
		}

	}

}
